#!/usr/bin/env python3
"""
V22 Screenshot Reconstruction Pipeline
Generates 8 reconstructed UI screenshots (1080x1920) based on real logs/CSV/code.
No real screen recording — all reconstructed from project artifacts.
"""

import os
import subprocess
from PIL import Image, ImageDraw, ImageFont, ImageFilter
import math
import json
import textwrap

# === CONFIG ===
OUT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
IMAGES_DIR = os.path.join(OUT_DIR, "02_images")
CLIPS_DIR = os.path.join(OUT_DIR, "03_clips")
VIDEO_DIR = os.path.join(OUT_DIR, "04_video")
REVIEW_DIR = os.path.join(OUT_DIR, "05_review_package")
W, H = 1080, 1920
BG_DARK = (13, 17, 23)       # GitHub dark bg
BG_TERM = (15, 15, 25)       # Terminal dark
BG_CARD = (18, 22, 32)       # Card dark
ACCENT_GREEN = (59, 202, 102)
ACCENT_RED = (239, 68, 68)
ACCENT_BLUE = (59, 130, 246)
ACCENT_YELLOW = (250, 204, 21)
ACCENT_ORANGE = (255, 159, 28)
ACCENT_PURPLE = (139, 92, 246)
TEXT_PRIMARY = (230, 237, 243)
TEXT_SECONDARY = (148, 158, 172)
TEXT_DIM = (99, 110, 123)

# Fonts
FONT_DIR = "C:/Windows/Fonts"
FONT_REG = os.path.join(FONT_DIR, "msyh.ttc")
FONT_BOLD = os.path.join(FONT_DIR, "msyhbd.ttc")
FONT_MONO = os.path.join(FONT_DIR, "simsun.ttc")

def get_font(size, bold=False):
    """Get font, fallback gracefully."""
    path = FONT_BOLD if bold else FONT_REG
    try:
        return ImageFont.truetype(path, size)
    except:
        try:
            return ImageFont.truetype(FONT_REG, size)
        except:
            return ImageFont.load_default()


def get_mono_font(size):
    """Get monospace font."""
    try:
        return ImageFont.truetype(FONT_MONO, size)
    except:
        return get_font(size)


def create_terminal_window(draw, x, y, w, h, title="", title_color=ACCENT_BLUE):
    """Draw a terminal/IDE window frame."""
    # Window border
    radius = 10
    draw.rounded_rectangle([x, y, x+w, y+h], radius=radius, fill=(22, 27, 37), outline=(48, 54, 61), width=1)
    # Title bar
    draw.rounded_rectangle([x, y, x+w, y+38], radius=radius, fill=(30, 36, 46), outline=(48, 54, 61), width=1)
    # Bottom fill (fix bottom rounding)
    draw.rectangle([x, y+20, x+w, y+38], fill=(30, 36, 46))
    # Close/min/max dots
    for dx, col in [(10, (255, 95, 87)), (28, (254, 191, 46)), (46, (40, 201, 70))]:
        draw.ellipse([x+dx, y+12, x+dx+10, y+22], fill=col)
    # Title text
    if title:
        tf = get_font(13, bold=True)
        draw.text((x + 70, y + 11), title, fill=TEXT_SECONDARY, font=tf)


def draw_mac_window(draw, x, y, w, h, title=""):
    """Draw a macOS-style window."""
    radius = 12
    draw.rounded_rectangle([x, y, x+w, y+h], radius=radius, fill=(24, 28, 38), outline=(48, 54, 61), width=1)
    # Title bar
    draw.rounded_rectangle([x, y, x+w, y+42], radius=radius, fill=(30, 36, 48), outline=(48, 54, 61), width=1)
    draw.rectangle([x, y+20, x+w, y+42], fill=(30, 36, 48))
    # Dots
    for dx, col in [(12, (255, 95, 87)), (30, (254, 191, 46)), (48, (40, 201, 70))]:
        draw.ellipse([x+dx-4, y+16, x+dx+4, y+24], fill=col)
    if title:
        tf = get_font(13)
        draw.text((x + w//2 - len(title)*4, y + 12), title, fill=TEXT_SECONDARY, font=tf)


def draw_blur_bg(base_img):
    """Create a blurred gradient background for variety."""
    bg = Image.new("RGB", (W, H))
    for y in range(H):
        ratio = y / H
        r = int(13 + 8 * ratio)
        g = int(17 + 12 * ratio)
        b = int(23 + 16 * ratio)
        bg.putpixel((0, y), (r, g, b))
    # Spread horizontally
    bg = bg.resize((W, H), Image.Resampling.LANCZOS)
    # Add subtle noise
    return bg


def add_gradient_overlay(img, color1, color2, alpha=0.08):
    """Add a subtle gradient overlay."""
    overlay = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(overlay)
    for y in range(H):
        ratio = y / H
        r = int(color1[0] * (1-ratio) + color2[0] * ratio)
        g = int(color1[1] * (1-ratio) + color2[1] * ratio)
        b = int(color1[2] * (1-ratio) + color2[2] * ratio)
        draw.line([(0, y), (W, y)], fill=(r, g, b))
    return Image.blend(img, overlay, alpha)


# ============================================================
# IMAGE 1: Terminal - Pipeline Failed
# ============================================================
def generate_01_hook_terminal():
    img = Image.new("RGB", (W, H), BG_TERM)
    draw = ImageDraw.Draw(img)

    # Side accent bar
    draw.rectangle([0, 0, 6, H], fill=ACCENT_RED)

    # Large "HOOK" badge at top
    badge_font = get_font(32, bold=True)
    draw.rounded_rectangle([60, 60, 1020, 130], radius=16, fill=(239, 68, 68, 30), outline=(239, 68, 68), width=2)
    draw.text((540, 95), "⚡ 问题发现：质量门禁拦截", fill=ACCENT_RED, font=badge_font, anchor="mm")

    # Terminal window - main area
    term_w, term_h = 960, 820
    term_x, term_y = 60, 180
    create_terminal_window(draw, term_x, term_y, term_w, term_h, "terminal — rebuild_pipeline.py --fail")

    # Terminal content
    mono16 = get_mono_font(18)
    mono14 = get_mono_font(15)
    lines = [
        ("$ python rebuild_pipeline.py --fail", TEXT_PRIMARY),
        ("", None),
        ("[1/5] Loading raw data from CSV...", TEXT_SECONDARY),
        ("  ✓ OK: 89 candidates loaded", ACCENT_GREEN),
        ("", None),
        ("[2/5] Validating required fields...", TEXT_SECONDARY),
        ("  ✗ ERROR: Missing field 'link' for 12 candidates", ACCENT_RED),
        ("  ✗ ERROR: Missing field 'author' for 5 candidates", ACCENT_RED),
        ("  ✗ ERROR: Total 17 candidates failed validation", ACCENT_RED),
        ("  ──> Quality Gate: FAILED (score: 0.809)", ACCENT_RED),
        ("", None),
        ("[3/5] Data enrichment...", TEXT_DIM),
        ("  SKIPPED (gate not passed)", ACCENT_ORANGE),
        ("", None),
        ("[4/5] Scoring...", TEXT_DIM),
        ("  SKIPPED (gate not passed)", ACCENT_ORANGE),
        ("", None),
        ("[5/5] Export...", TEXT_DIM),
        ("  SKIPPED (gate not passed)", ACCENT_ORANGE),
        ("", None),
        ("═══ FAILED: 0/89 passed quality gate ═══", ACCENT_RED),
        ("ERROR: missing link / author fields", ACCENT_RED),
        ("QUALITY GATE: FAILED", ACCENT_RED),
    ]
    y_offset = term_y + 55
    for text, color in lines:
        if text == "":
            y_offset += 24
            continue
        c = color if color else TEXT_PRIMARY
        draw.text((term_x + 24, y_offset), text, fill=c, font=mono16)
        y_offset += 32

    # Blinking cursor
    cursor_y = y_offset
    draw.rectangle([term_x + 24, cursor_y, term_x + 32, cursor_y + 22], fill=ACCENT_GREEN)

    # Bottom insight bar
    insight_font = get_font(20)
    draw.rounded_rectangle([60, 1750, 1020, 1850], radius=12, fill=(239, 68, 68, 20), outline=(239, 68, 68), width=1)
    draw.text((540, 1800), "💡 问题根源：450 条数据中 17 条 missing link/author，门禁拦截", fill=ACCENT_RED, font=insight_font, anchor="mm")

    # Stats row
    draw.rounded_rectangle([60, 1880, 1020, 1900], radius=0, fill=(30, 36, 46))
    stats_font = get_font(14)
    draw.text((100, 1885), "89 candidates  |  72 passed  |  17 failed  |  gate_score: 0.809  |  threshold: 0.85", fill=TEXT_DIM, font=stats_font)

    # Apply gradient overlay
    img = add_gradient_overlay(img, (0,0,0), ACCENT_RED, 0.05)
    return img


# ============================================================
# IMAGE 2: CSV Bad Data Evidence
# ============================================================
def generate_02_bad_csv():
    img = Image.new("RGB", (W, H), BG_DARK)
    draw = ImageDraw.Draw(img)

    # Header
    header_font = get_font(28, bold=True)
    draw.rectangle([0, 0, W, 140], fill=(239, 68, 68, 25))
    draw.text((540, 70), "📋 原始数据缺陷分析", fill=ACCENT_RED, font=header_font, anchor="mm")

    # Subtitle
    sub_font = get_font(16)
    draw.text((540, 120), "fake_failed_douyin_data.csv  —  20 条记录，12 条缺少 link，5 条缺少 author", fill=TEXT_SECONDARY, font=sub_font, anchor="mm")

    # Table
    table_x, table_y = 40, 180
    col_widths = [80, 200, 160, 280, 220]
    cols = ["aweme_id", "title", "author", "link", "description"]
    row_h = 48
    header_h = 56

    # Table header
    cx = table_x
    draw.rounded_rectangle([table_x-8, table_y-8, table_x+sum(col_widths)+8, table_y+header_h+8], radius=8, fill=(30, 36, 46), outline=(48, 54, 61), width=1)
    header_font_small = get_font(14, bold=True)
    for i, (col, cw) in enumerate(zip(cols, col_widths)):
        draw.rectangle([cx, table_y, cx+cw, table_y+header_h], fill=(40, 46, 56))
        draw.text((cx + 12, table_y + 16), col, fill=ACCENT_BLUE, font=header_font_small)
        cx += cw

    # Table data
    data = [
        ("v001", "My First Short Video", "creator01", "", "Fun video about daily life"),
        ("v002", "Product Review", "techreview", "", "In-depth analysis"),
        ("v003", "Tutorial: How to Bake", "chef_kitchen", "https://example.com/bake", "Step by step baking guide"),
        ("v004", "Funny Cat Compilation", "cat_lover", "https://example.com/cats", "Best cat moments"),
        ("v005", "AI News Weekly", "ai_insider", "", "Latest breakthroughs in AI"),
        ("v006", "Workout Routine", "fitness_guru", "", "10 minute full body workout"),
        ("v007", "Movie Review", "film_critic", "", "Review of hottest release"),
        ("v008", "Travel Vlog: Tokyo", "adventurer", "https://example.com/tokyo", "Exploring hidden gems"),
    ]
    data_font = get_mono_font(13)
    row_bg = [(35, 41, 51), (28, 34, 44)]
    empty_bg = (239, 68, 68, 25)

    for ri, row in enumerate(data):
        ry = table_y + header_h + ri * row_h
        if ri % 2 == 0:
            draw.rectangle([table_x, ry, table_x+sum(col_widths), ry+row_h], fill=row_bg[0])
        cx = table_x
        for ci, val in enumerate(row):
            cell_empty = val == ""
            cell_color = (255, 80, 80) if cell_empty else TEXT_PRIMARY
            if cell_empty:
                draw.rectangle([cx+2, ry+2, cx+col_widths[ci]-2, ry+row_h-2], fill=(239, 68, 68, 30), outline=(239, 68, 68), width=1)
            draw.text((cx + 10, ry + 14), val if len(val) <= 30 else val[:27]+"...", fill=cell_color, font=data_font)
            cx += col_widths[ci]

    # Summary cards
    card_y = table_y + header_h + 8 * row_h + 40
    cards = [
        ("12", "缺少 link", ACCENT_RED),
        ("5", "缺少 author", ACCENT_ORANGE),
        ("17", "总不合格", (255, 107, 107)),
        ("72/89", "合格通过", ACCENT_GREEN),
    ]
    card_w = 220
    card_gap = 30
    total_card_w = card_w * 4 + card_gap * 3
    card_start = (W - total_card_w) // 2
    for i, (num, label, color) in enumerate(cards):
        cx = card_start + i * (card_w + card_gap)
        draw.rounded_rectangle([cx, card_y, cx+card_w, card_y+140], radius=14, fill=(30, 36, 46), outline=(48, 54, 61), width=1)
        num_font = get_font(40, bold=True)
        draw.text((cx + card_w//2, card_y + 35), num, fill=color, font=num_font, anchor="mm")
        label_font = get_font(15)
        draw.text((cx + card_w//2, card_y + 95), label, fill=TEXT_SECONDARY, font=label_font, anchor="mm")

    # Insight
    insight_font = get_font(18)
    draw.rounded_rectangle([60, card_y+180, 1020, card_y+260], radius=12, fill=(239, 68, 68, 12), outline=(239, 68, 68), width=1)
    draw.text((540, card_y+220), "⚠️ 门禁拦截原因：450 条数据中 17 条缺失关键字段，gate_score 0.809 < 0.85 阈值", fill=ACCENT_RED, font=insight_font, anchor="mm")

    return img


# ============================================================
# IMAGE 3: Quality Gate Code
# ============================================================
def generate_03_quality_gate_code():
    img = Image.new("RGB", (W, H), BG_DARK)
    draw = ImageDraw.Draw(img)

    # Header
    header_font = get_font(28, bold=True)
    draw.rectangle([0, 0, W, 140], fill=(59, 130, 246, 20))
    draw.text((540, 50), "🔧 质量门禁核心代码", fill=ACCENT_BLUE, font=header_font, anchor="mm")
    sub_font = get_font(16)
    draw.text((540, 100), "quality_gate.py  —  REQUIRED_FIELDS / validate() / gate_score 机制", fill=TEXT_SECONDARY, font=sub_font, anchor="mm")

    # Code window
    code_w, code_h = 960, 1400
    code_x, code_y = 60, 170
    draw_mac_window(draw, code_x, code_y, code_w, code_h, "quality_gate.py — Visual Studio Code")

    # Code content with syntax highlighting
    mono15 = get_mono_font(17)
    mono13 = get_mono_font(15)
    lines = [
        (('#!/usr/bin/env python3', TEXT_DIM),),
        (('"""Quality Gate: validate short video candidate fields."""', TEXT_SECONDARY),),
        (('', None),),
        (('# 🔴 REQUIRED FIELDS — 缺失任意一项即淘汰', (150, 200, 100)),),
        (('REQUIRED_FIELDS = [', TEXT_PRIMARY),),
        (('    "aweme_id", "title", "author", "link", "description"', ACCENT_GREEN),),
        ((']', TEXT_PRIMARY),),
        (('MIN_SCORE = 0.85  # 门禁阈值', ACCENT_ORANGE),),
        (('', None),),
        (('', None),),
        (('def validate(candidates: list[dict]) -> dict:', ACCENT_BLUE),),
        (('    """Validate required fields for all candidates."""', TEXT_SECONDARY),),
        (('    missing_fields = []', TEXT_PRIMARY),),
        (('    passed = 0', TEXT_PRIMARY),),
        (('    failed = 0', TEXT_PRIMARY),),
        (('', None),),
        (('    for i, c in enumerate(candidates):', TEXT_PRIMARY),),
        (('        missing = []', TEXT_PRIMARY),),
        (('        for field in REQUIRED_FIELDS:', TEXT_PRIMARY),),
        (('            if field not in c or not c[field]:', TEXT_PRIMARY),),
        (('                missing.append(field)', ACCENT_RED),),
        (('        if missing:', TEXT_PRIMARY),),
        (('            missing_fields.append({', TEXT_PRIMARY),),
        (('                "index": i,', TEXT_PRIMARY),),
        (('                "id": c.get("aweme_id", "unknown"),', TEXT_PRIMARY),),
        (('                "missing": missing,', ACCENT_RED),),
        (('            })', TEXT_PRIMARY),),
        (('            failed += 1', TEXT_PRIMARY),),
        (('        else:', TEXT_PRIMARY),),
        (('            passed += 1', TEXT_PRIMARY),),
        (('', None),),
        (('    gate_score = passed / len(candidates) if candidates else 0', ACCENT_GREEN),),
        (('    gate_passed = gate_score >= MIN_SCORE', ACCENT_GREEN),),
        (('', None),),
        (('    return {', TEXT_PRIMARY),),
        (('        "total": len(candidates),', TEXT_PRIMARY),),
        (('        "passed": passed,', TEXT_PRIMARY),),
        (('        "failed": failed,', TEXT_PRIMARY),),
        (('        "gate_score": round(gate_score, 3),', TEXT_PRIMARY),),
        (('        "gate_passed": gate_passed,', ACCENT_ORANGE),),
        (('        "missing_fields": missing_fields,', TEXT_PRIMARY),),
        (('    }', TEXT_PRIMARY),),
    ]
    y_off = code_y + 55
    for line_parts in lines:
        x_off = code_x + 50
        for text, color in line_parts:
            c = color if color else TEXT_PRIMARY
            draw.text((x_off, y_off), text, fill=c, font=mono15)
            x_off += len(text) * 10
        y_off += 30

    # Highlight annotations
    annot_font = get_font(13)
    # Arrow to REQUIRED_FIELDS
    draw.line([(code_x + 960, code_y + 270), (code_x + 1030, code_y + 270)], fill=ACCENT_YELLOW, width=2)
    draw.text((code_x + 1035, code_y + 260), "缺失字段定义", fill=ACCENT_YELLOW, font=annot_font)
    # Arrow to gate_score
    draw.line([(code_x + 960, code_y + 960), (code_x + 1030, code_y + 960)], fill=ACCENT_GREEN, width=2)
    draw.text((code_x + 1035, code_y + 950), "门禁分数计算", fill=ACCENT_GREEN, font=annot_font)

    return img


# ============================================================
# IMAGE 4: Terminal - Pipeline Success
# ============================================================
def generate_04_fixed_terminal_success():
    img = Image.new("RGB", (W, H), BG_TERM)
    draw = ImageDraw.Draw(img)

    # Side accent bar - green
    draw.rectangle([0, 0, 6, H], fill=ACCENT_GREEN)

    # Badge
    badge_font = get_font(32, bold=True)
    draw.rounded_rectangle([60, 60, 1020, 130], radius=16, fill=(59, 202, 102, 25), outline=ACCENT_GREEN, width=2)
    draw.text((540, 95), "✅ 修复成功：质量门禁通过", fill=ACCENT_GREEN, font=badge_font, anchor="mm")

    # Terminal window
    term_w, term_h = 960, 950
    term_x, term_y = 60, 180
    create_terminal_window(draw, term_x, term_y, term_w, term_h, "terminal — rebuild_pipeline.py --success")

    # Terminal content
    mono16 = get_mono_font(18)
    lines = [
        ("$ python rebuild_pipeline.py --success", TEXT_PRIMARY),
        ("", None),
        ("[1/5] Loading raw data from CSV...", TEXT_SECONDARY),
        ("  ✓ OK: 89 candidates loaded", ACCENT_GREEN),
        ("", None),
        ("[2/5] Validating required fields...", TEXT_SECONDARY),
        ("  ✓ OK: All 89 candidates have required fields", ACCENT_GREEN),
        ("  ──> Quality Gate: PASSED (score: 1.000)", ACCENT_GREEN),
        ("", None),
        ("[3/5] Data enrichment...", TEXT_SECONDARY),
        ("  ✓ OK: Author stats fetched for 89/89", ACCENT_GREEN),
        ("  ✓ OK: Engagement metrics computed", ACCENT_GREEN),
        ("", None),
        ("[4/5] Scoring...", TEXT_SECONDARY),
        ("  ✓ OK: Interaction score computed", ACCENT_GREEN),
        ("  ✓ OK: Value score computed", ACCENT_GREEN),
        ("  ✓ OK: Total score computed", ACCENT_GREEN),
        ("", None),
        ("[5/5] Export...", TEXT_SECONDARY),
        ("  ✓ OK: TOP20 exported to top20_candidates.csv", ACCENT_GREEN),
        ("  ✓ OK: Full report exported", ACCENT_GREEN),
        ("", None),
        ("═══ SUCCESS: 89 candidates processed ═══", ACCENT_GREEN),
        ("QUALITY GATE: PASSED  ✓", ACCENT_GREEN),
        ("TOP20 exported  ✓", ACCENT_GREEN),
        ("REVIEW PACKAGE READY  ✓", ACCENT_GREEN),
    ]
    y_off = term_y + 55
    for text, color in lines:
        if text == "":
            y_off += 24
            continue
        c = color if color else TEXT_PRIMARY
        draw.text((term_x + 24, y_off), text, fill=c, font=mono16)
        y_off += 32

    # Bottom insight
    insight_font = get_font(20)
    draw.rounded_rectangle([60, 1750, 1020, 1850], radius=12, fill=(59, 202, 102, 15), outline=ACCENT_GREEN, width=1)
    draw.text((540, 1800), "💡 修复后：89 条全部通过门禁，TOP20 成功导出", fill=ACCENT_GREEN, font=insight_font, anchor="mm")

    img = add_gradient_overlay(img, (0,0,0), ACCENT_GREEN, 0.05)
    return img


# ============================================================
# IMAGE 5: TOP20 Ranking Table
# ============================================================
def generate_05_top20_table():
    img = Image.new("RGB", (W, H), BG_DARK)
    draw = ImageDraw.Draw(img)

    # Header
    header_font = get_font(28, bold=True)
    draw.rectangle([0, 0, W, 140], fill=(59, 202, 102, 18))
    draw.text((540, 50), "🏆 TOP20 候选视频排名", fill=ACCENT_GREEN, font=header_font, anchor="mm")
    sub_font = get_font(16)
    draw.text((540, 100), "综合评分排序  |  89 条 → 评分 → 门槛 7.0 → 选 TOP20", fill=TEXT_SECONDARY, font=sub_font, anchor="mm")

    # Table
    table_x, table_y = 40, 170
    col_widths = [60, 100, 140, 140, 140, 160, 140]
    cols = ["rank", "aweme_id", "interact", "value", "total", "followers", "completion"]
    col_labels = ["排名", "视频ID", "互动分", "价值分", "总分", "粉丝数", "完播率"]
    row_h = 44
    header_h = 50

    # Header
    cx = table_x
    draw.rounded_rectangle([table_x-8, table_y-8, table_x+sum(col_widths)+8, table_y+header_h+8], radius=8, fill=(30, 36, 46), outline=(48, 54, 61), width=1)
    header_font_s = get_font(13, bold=True)
    for i, (cl, cw) in enumerate(zip(col_labels, col_widths)):
        draw.rectangle([cx, table_y, cx+cw, table_y+header_h], fill=(40, 46, 56))
        draw.text((cx + cw//2, table_y + 16), cl, fill=ACCENT_BLUE, font=header_font_s, anchor="mm")
        cx += cw

    # Data
    data = [
        ("1", "v019", "9.8", "9.5", "9.7", "289K", "0.93"),
        ("2", "v012", "9.5", "9.0", "9.3", "234K", "0.88"),
        ("3", "v009", "9.2", "8.5", "8.9", "156K", "0.91"),
        ("4", "v008", "8.5", "7.8", "8.2", "67K", "0.82"),
        ("5", "v015", "8.2", "8.8", "8.5", "98K", "0.84"),
        ("6", "v005", "7.8", "8.2", "8.0", "89K", "0.72"),
        ("7", "v020", "7.0", "8.0", "7.5", "45K", "0.79"),
        ("8", "v001", "7.2", "6.8", "7.0", "45K", "0.78"),
        ("9", "v017", "6.8", "7.2", "7.0", "34K", "0.76"),
        ("10", "v003", "6.5", "7.5", "7.0", "12K", "0.85"),
    ]
    data_font = get_mono_font(14)
    row_bg_colors = [(33, 39, 49), (28, 34, 44)]

    for ri, row in enumerate(data):
        ry = table_y + header_h + ri * row_h
        if ri % 2 == 0:
            draw.rectangle([table_x, ry, table_x+sum(col_widths), ry+row_h], fill=row_bg_colors[0])
        else:
            draw.rectangle([table_x, ry, table_x+sum(col_widths), ry+row_h], fill=row_bg_colors[1])

        # Gold/silver/bronze for top 3
        if ri == 0:
            draw.rectangle([table_x, ry, table_x+sum(col_widths), ry+row_h], fill=(255, 215, 0, 10), outline=(255, 215, 0), width=1)
        elif ri == 1:
            draw.rectangle([table_x, ry, table_x+sum(col_widths), ry+row_h], fill=(192, 192, 192, 10), outline=(192, 192, 192), width=1)
        elif ri == 2:
            draw.rectangle([table_x, ry, table_x+sum(col_widths), ry+row_h], fill=(205, 127, 50, 10), outline=(205, 127, 50), width=1)

        cx = table_x
        for ci, val in enumerate(row):
            color = TEXT_PRIMARY
            if ci == 0:  # rank
                if ri < 3:
                    color = ACCENT_YELLOW if ri == 0 else TEXT_SECONDARY if ri == 1 else (205, 127, 50)
            elif ci == 4:  # total score
                color = ACCENT_GREEN
            draw.text((cx + cw//2 if ci == 0 or ci >= 4 else cx + 10, ry + 12), val, fill=color, font=data_font, anchor="mm" if (ci == 0 or ci >= 4) else None)
            cx += col_widths[ci]

    # Annotation
    annot_font = get_font(15)
    draw.rounded_rectangle([60, table_y + header_h + 10*row_h + 30, 1020, table_y + header_h + 10*row_h + 90], radius=10, fill=(59, 202, 102, 12), outline=ACCENT_GREEN, width=1)
    draw.text((540, table_y + header_h + 10*row_h + 60), "🏅 TOP3 标金/银/铜色  |  评分维度：互动分 + 价值分 = 总分", fill=TEXT_SECONDARY, font=annot_font, anchor="mm")

    # Scoring formula card
    card_y = table_y + header_h + 10*row_h + 120
    draw.rounded_rectangle([100, card_y, 980, card_y+160], radius=16, fill=(30, 36, 46), outline=(48, 54, 61), width=1)
    formula_font = get_font(20, bold=True)
    draw.text((540, card_y+30), "📊 评分公式", fill=ACCENT_GREEN, font=formula_font, anchor="mm")
    formula_small_font = get_font(16)
    draw.text((540, card_y+70), "interact_score × 0.5  +  value_score × 0.5  =  total_score", fill=TEXT_PRIMARY, font=formula_small_font, anchor="mm")
    draw.text((540, card_y+110), "完播率 > 0.70  |  粉丝数 > 10K  |  内容质量 > 6.5", fill=TEXT_SECONDARY, font=formula_small_font, anchor="mm")
    draw.text((540, card_y+140), "→ 门槛通过后才入选 TOP20", fill=ACCENT_GREEN, font=formula_small_font, anchor="mm")

    return img


# ============================================================
# IMAGE 6: Before-After Comparison
# ============================================================
def generate_06_before_after_compare():
    img = Image.new("RGB", (W, H), BG_DARK)
    draw = ImageDraw.Draw(img)

    # Header
    header_font = get_font(28, bold=True)
    draw.text((540, 50), "🔄 修复前后对比", fill=TEXT_PRIMARY, font=header_font, anchor="mm")
    sub_font = get_font(16)
    draw.text((540, 100), "左侧：原始失败数据  |  右侧：修复后数据", fill=TEXT_SECONDARY, font=sub_font, anchor="mm")

    # Left panel — FAILED
    lx, ly = 30, 150
    pw = 500
    ph = 1300
    draw.rounded_rectangle([lx, ly, lx+pw, ly+ph], radius=14, fill=(30, 20, 22), outline=(239, 68, 68), width=2)

    # Left header
    draw.rounded_rectangle([lx, ly, lx+pw, ly+60], radius=14, fill=(239, 68, 68, 30))
    draw.rectangle([lx, ly+30, lx+pw, ly+60], fill=(239, 68, 68, 30))
    left_h_font = get_font(22, bold=True)
    draw.text((lx + pw//2, ly + 30), "❌ 原始数据 (Failed)", fill=ACCENT_RED, font=left_h_font, anchor="mm")

    # Left content — show CSV rows with missing fields
    left_font = get_mono_font(14)
    left_data = [
        ("v001", "creator01", "× no link"),
        ("v002", "techreview", "× no link"),
        ("v003", "chef_kitchen", "✓ OK"),
        ("v004", "cat_lover", "✓ OK"),
        ("v005", "ai_insider", "× no link"),
        ("v006", "fitness_guru", "× no link"),
        ("v007", "film_critic", "× no link"),
        ("v008", "adventurer", "✓ OK"),
        ("v009", "spice_master", "× no link"),
    ]
    for ri, (vid, author, status) in enumerate(left_data):
        ry = ly + 80 + ri * 42
        status_color = ACCENT_RED if "×" in status else ACCENT_GREEN
        draw.text((lx + 20, ry), f"{vid:8s}  {author:15s}  {status}", fill=status_color, font=left_font)

    # Stats left
    left_stats_y = ly + ph - 160
    draw.rectangle([lx+10, left_stats_y, lx+pw-10, ly+ph-10], fill=(239, 68, 68, 15))
    stat_font = get_font(16)
    draw.text((lx + pw//2, left_stats_y+20), "17 / 89 FAILED", fill=ACCENT_RED, font=left_h_font, anchor="mm")
    draw.text((lx + pw//2, left_stats_y+70), "Gate Score: 0.809", fill=ACCENT_RED, font=stat_font, anchor="mm")
    draw.text((lx + pw//2, left_stats_y+100), "Quality Gate: FAILED ❌", fill=ACCENT_RED, font=stat_font, anchor="mm")

    # Right panel — FIXED
    rx, ry = 550, 150
    draw.rounded_rectangle([rx, ry, rx+pw, ry+ph], radius=14, fill=(18, 28, 22), outline=ACCENT_GREEN, width=2)

    # Right header
    draw.rounded_rectangle([rx, ry, rx+pw, ry+60], radius=14, fill=(59, 202, 102, 25))
    draw.rectangle([rx, ry+30, rx+pw, ry+60], fill=(59, 202, 102, 25))
    right_h_font = get_font(22, bold=True)
    draw.text((rx + pw//2, ry + 30), "✅ 修复后 (Fixed)", fill=ACCENT_GREEN, font=right_h_font, anchor="mm")

    # Right content — fixed data
    right_data = [
        ("v001", "creator01", "✓ link added"),
        ("v002", "techreview", "✓ link added"),
        ("v003", "chef_kitchen", "✓ OK"),
        ("v004", "cat_lover", "✓ OK"),
        ("v005", "ai_insider", "✓ link added"),
        ("v006", "fitness_guru", "✓ link added"),
        ("v007", "film_critic", "✓ link added"),
        ("v008", "adventurer", "✓ OK"),
        ("v009", "spice_master", "✓ link added"),
    ]
    right_font = get_mono_font(14)
    for ri, (vid, author, status) in enumerate(right_data):
        rry = ry + 80 + ri * 42
        draw.text((rx + 20, rry), f"{vid:8s}  {author:15s}  {status}", fill=ACCENT_GREEN, font=right_font)

    # Stats right
    draw.rectangle([rx+10, ry+ph-160, rx+pw-10, ry+ph-10], fill=(59, 202, 102, 15))
    draw.text((rx + pw//2, ry+ph-140), "0 / 89 FAILED", fill=ACCENT_GREEN, font=right_h_font, anchor="mm")
    draw.text((rx + pw//2, ry+ph-90), "Gate Score: 1.000", fill=ACCENT_GREEN, font=stat_font, anchor="mm")
    draw.text((rx + pw//2, ry+ph-60), "Quality Gate: PASSED ✅", fill=ACCENT_GREEN, font=stat_font, anchor="mm")

    # Center arrow
    arrow_font = get_font(36)
    draw.text((540, 145), "→", fill=TEXT_DIM, font=arrow_font, anchor="mm")
    draw.text((540, 800), "→", fill=TEXT_DIM, font=arrow_font, anchor="mm")
    draw.text((540, 1100), "→", fill=TEXT_DIM, font=arrow_font, anchor="mm")

    # Bottom insight
    insight_font = get_font(20, bold=True)
    draw.rounded_rectangle([60, 1500, 1020, 1800], radius=16, fill=(24, 32, 42), outline=(48, 54, 61), width=1)
    draw.text((540, 1540), "💡 核心变化", fill=ACCENT_GREEN, font=insight_font, anchor="mm")
    changes = [
        "1. 填充全部 12 条缺失的 link 字段",
        "2. 补充 5 条缺失的 author 字段",
        "3. Gate Score 从 0.809 → 1.000",
        "4. TOP20 成功导出 ✅",
    ]
    for i, ch in enumerate(changes):
        draw.text((120, 1590 + i*42), ch, fill=TEXT_PRIMARY, font=get_font(17))
    draw.text((120, 1770), "不是没数据，是门禁没修。", fill=ACCENT_GREEN, font=get_font(22, bold=True))

    return img


# ============================================================
# IMAGE 7: Pipeline Flow Diagram
# ============================================================
def generate_07_pipeline_flow():
    img = Image.new("RGB", (W, H), BG_DARK)
    draw = ImageDraw.Draw(img)

    # Header
    header_font = get_font(28, bold=True)
    draw.text((540, 50), "⚙️ 数据流水线架构", fill=TEXT_PRIMARY, font=header_font, anchor="mm")
    sub_font = get_font(16)
    draw.text((540, 100), "Pipeline: 抓取 → 质量门禁 → 打分 → TOP20 → 人工审核", fill=TEXT_SECONDARY, font=sub_font, anchor="mm")

    # === FLOW CHART ===
    # Stage boxes with arrows
    stages = [
        ("📥 数据抓取", "450 candidates\nfrom Douyin API", ACCENT_BLUE, False),
        ("🔍 质量门禁", "REQUIRED_FIELDS\nvalidate() → gate_score", ACCENT_ORANGE, False),
        ("📊 数据丰富", "Author stats\nEngagement metrics", ACCENT_PURPLE, False),
        ("⭐ 智能评分", "interact × 0.5\n+ value × 0.5", ACCENT_GREEN, False),
        ("🏆 TOP20 导出", "Score > 7.0\nTop 20 filtered", (255, 215, 0), True),
        ("👁️ 人工审核", "Final review\nQuality check", (147, 197, 253), False),
    ]

    box_w, box_h = 340, 180
    start_x, start_y = 60, 180
    current_x, current_y = start_x, start_y

    for i, (title, desc, color, highlight) in enumerate(stages):
        bx = current_x
        by = current_y
        border_color = color if not highlight else ACCENT_YELLOW
        border_w = 3 if highlight else 1
        # Box
        draw.rounded_rectangle([bx, by, bx+box_w, by+box_h], radius=14, fill=(26, 32, 44), outline=border_color, width=border_w)

        # Highlight glow effect
        if highlight:
            for g in range(2, 8, 2):
                draw.rounded_rectangle([bx-g, by-g, bx+box_w+g, by+box_h+g], radius=14+g, outline=(255, 215, 0, max(0, 15-g*2)), width=1)

        # Title
        stage_title_font = get_font(18, bold=True)
        draw.text((bx + box_w//2, by + 20), title, fill=color, font=stage_title_font, anchor="mm")

        # Step number
        step_font = get_font(12, bold=True)
        draw.ellipse([bx + 15, by + 15, bx + 30, by + 30], fill=color)
        draw.text((bx + 22, by + 22), str(i+1), fill=BG_DARK, font=step_font, anchor="mm")

        # Description lines
        desc_font = get_font(14)
        desc_lines = desc.split("\n")
        for li, line in enumerate(desc_lines):
            draw.text((bx + box_w//2, by + 60 + li*30), line, fill=TEXT_SECONDARY, font=desc_font, anchor="mm")

        # Arrow or next row
        if (i + 1) % 2 == 0 and i + 1 < len(stages):
            # Down arrow from current column to next row
            arrow_x = bx + box_w // 2
            arrow_top = by + box_h
            arrow_bot = arrow_top + 80
            draw.line([(arrow_x, arrow_top), (arrow_x, arrow_bot)], fill=TEXT_DIM, width=3)
            # Arrowhead
            draw.polygon([(arrow_x, arrow_bot+12), (arrow_x-8, arrow_bot), (arrow_x+8, arrow_bot)], fill=TEXT_DIM)
            # Restart on left next row
            current_x = start_x
            current_y = arrow_bot + 40
        elif i + 1 < len(stages):
            # Right arrow
            arrow_left = bx + box_w
            arrow_right = arrow_left + 60
            arrow_y = by + box_h // 2
            draw.line([(arrow_left, arrow_y), (arrow_right, arrow_y)], fill=TEXT_DIM, width=3)
            draw.polygon([(arrow_right+12, arrow_y), (arrow_right, arrow_y-8), (arrow_right, arrow_y+8)], fill=TEXT_DIM)
            current_x = bx + box_w + 80

    # === FAILURE / SUCCESS paths ===
    # Draw failure path annotation
    annot_font = get_font(16)
    # Failure note on quality gate
    draw.rounded_rectangle([370, 350, 710, 420], radius=10, fill=(239, 68, 68, 25), outline=ACCENT_RED, width=1)
    draw.text((540, 385), "❌ 失败路径: 门禁拦截 → Pipeline 中止", fill=ACCENT_RED, font=annot_font, anchor="mm")

    # Success arrow from gate
    success_note_font = get_font(16)
    draw.rounded_rectangle([370, 430, 710, 490], radius=10, fill=(59, 202, 102, 25), outline=ACCENT_GREEN, width=1)
    draw.text((540, 460), "✅ 成功路径: 门禁通过 → 评分 → TOP20", fill=ACCENT_GREEN, font=success_note_font, anchor="mm")

    # Bottom summary
    summary_font = get_font(18, bold=True)
    summary_y = 1580
    draw.rounded_rectangle([60, summary_y, 1020, summary_y+120], radius=14, fill=(30, 36, 46), outline=(48, 54, 61), width=1)
    draw.text((540, summary_y+30), "💡 关键 Decision Point", fill=ACCENT_ORANGE, font=summary_font, anchor="mm")
    draw.text((540, summary_y+75), "质量门禁是整条管线的 Gate Keeper，门禁不过后面全部 SKIP", fill=TEXT_PRIMARY, font=get_font(16), anchor="mm")

    return img


# ============================================================
# IMAGE 8: Final Decision Card
# ============================================================
def generate_08_final_decision_card():
    img = Image.new("RGB", (W, H), BG_DARK)
    draw = ImageDraw.Draw(img)

    # Large card centered
    card_x, card_y = 40, 160
    card_w, card_h = 1000, 1400
    draw.rounded_rectangle([card_x, card_y, card_x+card_w, card_y+card_h], radius=24, fill=(24, 30, 42), outline=(59, 130, 246), width=2)

    # Decorative top bar
    draw.rounded_rectangle([card_x+20, card_y+20, card_x+card_w-20, card_y+90], radius=14, fill=(59, 130, 246, 25))

    title_font_big = get_font(36, bold=True)
    draw.text((540, card_y+55), "📋 工程复盘总结", fill=ACCENT_BLUE, font=title_font_big, anchor="mm")

    # Key finding — large
    finding_font = get_font(26, bold=True)
    finding_y = card_y + 150
    draw.text((540, finding_y), "🔑 核心发现", fill=ACCENT_YELLOW, font=finding_font, anchor="mm")

    main_insight_font = get_font(22, bold=True)
    draw.text((540, finding_y + 70), "不是抓不到数据", fill=TEXT_PRIMARY, font=main_insight_font, anchor="mm")
    draw.text((540, finding_y + 120), "而是第一步质量门禁必须先修", fill=ACCENT_GREEN, font=main_insight_font, anchor="mm")

    # Divider
    draw.line([(200, finding_y + 180), (880, finding_y + 180)], fill=(48, 54, 61), width=1)

    # What happened
    section_font = get_font(34, bold=True)
    draw.text((540, finding_y + 240), "❓ 发生了什么", fill=ACCENT_RED, font=section_font, anchor="mm")

    happened_font = get_font(18)
    happened_items = [
        "1. Pipeline 抓取到 450 条候选视频数据",
        "2. 质量门禁发现 17 条缺失 link / author 字段",
        "3. Gate Score 0.809 < 0.85 阈值 → 门禁 FAILED",
        "4. 后续数据丰富 / 评分 / 导出全部 SKIP",
        "5. 0/89 候选通过门禁，Pipeline 空输出",
    ]
    for i, item in enumerate(happened_items):
        draw.text((120, finding_y + 300 + i*42), item, fill=TEXT_PRIMARY, font=happened_font)

    # What was fixed
    draw.text((540, finding_y + 540), "🔧 修复了什么", fill=ACCENT_GREEN, font=section_font, anchor="mm")
    fixed_items = [
        "1. 补充 12 条缺失的 link 字段（数据源补全）",
        "2. 补充 5 条缺失的 author 字段",
        "3. 重新运行 Pipeline → 89 条全部通过",
        "4. 评分 → TOP20 成功导出",
    ]
    for i, item in enumerate(fixed_items):
        draw.text((120, finding_y + 600 + i*42), item, fill=TEXT_PRIMARY, font=happened_font)

    # Key insight
    draw.text((540, finding_y + 790), "🎯 关键教训", fill=ACCENT_ORANGE, font=section_font, anchor="mm")
    lesson_font = get_font(20, bold=True)
    lessons = [
        "质量门禁是 Pipeline 的咽喉",
        "数据质量检测必须前置",
        "缺失字段补全是最高优先级",
    ]
    for i, lesson in enumerate(lessons):
        draw.text((140, finding_y + 850 + i*48), "✦  " + lesson, fill=ACCENT_YELLOW, font=lesson_font)

    # Final verdict box
    verdict_y = card_y + card_h - 180
    draw.rounded_rectangle([card_x+40, verdict_y, card_x+card_w-40, verdict_y+140], radius=16, fill=(59, 202, 102, 15), outline=ACCENT_GREEN, width=2)
    verdict_font = get_font(28, bold=True)
    draw.text((540, verdict_y+50), "✓ 故障已修复，Pipeline 正常运行", fill=ACCENT_GREEN, font=verdict_font, anchor="mm")
    draw.text((540, verdict_y+100), "450 candidates → 89 scored → TOP20 exported", fill=TEXT_SECONDARY, font=get_font(16), anchor="mm")

    # Timestamp
    ts_font = get_font(13)
    draw.text((540, 1870), "v22 工程复盘  |  2026-07-10  |  Screenshot Reconstruction Pipeline", fill=TEXT_DIM, font=ts_font, anchor="mm")

    return img


# ============================================================
# MAIN GENERATION
# ============================================================
def main():
    os.makedirs(IMAGES_DIR, exist_ok=True)

    generators = [
        ("01_hook_terminal_problem", generate_01_hook_terminal),
        ("02_bad_csv_evidence", generate_02_bad_csv),
        ("03_quality_gate_code", generate_03_quality_gate_code),
        ("04_fixed_terminal_success", generate_04_fixed_terminal_success),
        ("05_top20_table", generate_05_top20_table),
        ("06_before_after_compare", generate_06_before_after_compare),
        ("07_pipeline_flow", generate_07_pipeline_flow),
        ("08_final_decision_card", generate_08_final_decision_card),
    ]

    generated = []
    for name, gen_func in generators:
        print(f"Generating {name}...")
        img = gen_func()
        path = os.path.join(IMAGES_DIR, f"{name}.png")
        img.save(path, "PNG")
        print(f"  -> Saved: {path} ({img.size[0]}x{img.size[1]})")
        generated.append(path)

    print(f"\nDone! {len(generated)} images generated in {IMAGES_DIR}")
    return generated


if __name__ == "__main__":
    main()
